package avicit.bdp.dgs.metadata.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.service.dto.BdpColumnDTO;
import avicit.bdp.common.service.dto.BdpColumnHistoryDTO;
import avicit.bdp.common.service.dto.BdpTableDTO;
import avicit.bdp.common.service.dto.BdpTableHistoryDTO;
import avicit.bdp.common.utils.CheckParaUtils;
import avicit.bdp.common.utils.EntityUtils;
import avicit.bdp.common.utils.VersionUtil;
import avicit.bdp.core.datasource.enums.DataSourceType;
import avicit.bdp.core.enums.TableTypeEnum;
import avicit.bdp.dgs.metadata.dao.MetadataBusinessDao;
import avicit.bdp.dgs.metadata.dao.MetadataTmpDao;
import avicit.bdp.dgs.metadata.dto.MetadataBusinessDto;
import avicit.bdp.dgs.metadata.dto.MetadataColumnTmpDTO;
import avicit.bdp.dgs.metadata.dto.MetadataModelAttributeDTO;
import avicit.bdp.dgs.metadata.dto.MetadataTmpDTO;
import avicit.platform6.commons.utils.ComUtil;
import avicit.platform6.commons.utils.StringUtils;
import avicit.platform6.core.exception.DaoException;
import avicit.platform6.modules.system.syslog.service.SysLogUtil;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Transactional(rollbackFor = Exception.class)
@Service
public class MetadataTmpService extends BaseService<MetadataTmpDao, MetadataTmpDTO> {

  private static final Logger LOGGER = LoggerFactory.getLogger(MetadataTmpService.class);

  @Resource private MetadataColumnTmpService metadataColumnTmpService;
  @Resource private MetadataTableService metadataTableService;
  @Resource private MetadataTableHistoryService metadataTableHistoryService;
  @Resource private MetadataTableColumnService metadataTableColumnService;

  @Resource private MetadataBusinessDao metadataBusinessDao;

  @Resource private MetadataModelAttributeService metadataModelAttributeService;

  /**
   * 元数据结构有变更，自动保存一条记录
   *
   * @param dto 保存对象
   * @return String
   */
  @Transactional
  public String save(MetadataTmpDTO dto) {
    try {
      dto.setId(ComUtil.getId());
      this.insertWithoutVersion(dto);
      // 记录日志
      SysLogUtil.log4Insert(dto);
      return dto.getId();
    } catch (Exception e) {
      throw new DaoException(e.getMessage(), e);
    }
  }

  public MetadataTmpDTO queryByMetadataId(String metadataId) {
    CheckParaUtils.checkStringValidity(metadataId, LOGGER, "元数据ID不能为空");
    MetadataTmpDTO query = new MetadataTmpDTO();
    query.setMetadataId(metadataId);
    return this.selectOne(query);
  }

  public Boolean publish(String metadataId) {

    // 通过元数据ID查询记录
    MetadataTmpDTO metadataTmpDTO = this.queryByMetadataId(metadataId);
    CheckParaUtils.checkObjectValidity(metadataTmpDTO, LOGGER, "数据不存在");

    BdpTableDTO oldMetadata = metadataTableService.selectByPrimaryKey(metadataId);
    CheckParaUtils.checkObjectValidity(oldMetadata, LOGGER, "元数据不存在");

    MetadataColumnTmpDTO columnQuery = new MetadataColumnTmpDTO();
    columnQuery.setMetadataId(metadataId);
    List<MetadataColumnTmpDTO> columnTmpList = metadataColumnTmpService.selectList(columnQuery);

    if (CollectionUtils.isNotEmpty(columnTmpList)) {
      // 生成最新版本
      String newVersion = VersionUtil.generateVersion2Next(oldMetadata.getTableVersion());

      // 生成一条最新版本到元数据历史版本记录
      BdpTableHistoryDTO historyTableMetadata = new BdpTableHistoryDTO();
      BeanUtils.copyProperties(metadataTmpDTO, historyTableMetadata);
      historyTableMetadata.setId(ComUtil.getId());
      historyTableMetadata.setTableId(metadataId);
      historyTableMetadata.setTableVersion(newVersion);
      historyTableMetadata.setType(TableTypeEnum.TABLE_METADATA.getCode());
      EntityUtils.setCreateAndUpdateInfoWithoutVersion(historyTableMetadata);
      metadataTableHistoryService.insert(historyTableMetadata);

      // 生成一条最新元数据到元数据主表
      BdpTableDTO newTableMetadata = new BdpTableDTO();
      BeanUtils.copyProperties(metadataTmpDTO, newTableMetadata);
      newTableMetadata.setId(metadataId);
      newTableMetadata.setTableVersion(newVersion);
      EntityUtils.setCreateAndUpdateInfoWithoutVersion(newTableMetadata);
      newTableMetadata.setType(TableTypeEnum.TABLE_METADATA.getCode());
      metadataTableService.deleteByPrimaryKey(metadataId);
      metadataTableService.insert(newTableMetadata);

      List<BdpColumnDTO> columnList = new ArrayList<>(columnTmpList.size());
      List<BdpColumnHistoryDTO> historyColumnList = new ArrayList<>(columnTmpList.size());
      for (MetadataColumnTmpDTO metadataColumnTmpDTO : columnTmpList) {
        BdpColumnDTO columnDTO = new BdpColumnDTO();
        BeanUtils.copyProperties(metadataColumnTmpDTO, columnDTO);
        columnDTO.setTableId(metadataId);
        EntityUtils.setCreateAndUpdateInfoWithoutVersion(columnDTO);
        columnList.add(columnDTO);

        BdpColumnHistoryDTO columnHistoryDTO = new BdpColumnHistoryDTO();
        BeanUtils.copyProperties(metadataColumnTmpDTO, columnHistoryDTO);
        columnHistoryDTO.setId(ComUtil.getId());
        columnHistoryDTO.setTableId(historyTableMetadata.getId());
        EntityUtils.setCreateAndUpdateInfoWithoutVersion(columnHistoryDTO);
        historyColumnList.add(columnHistoryDTO);
      }

      metadataTableColumnService.deleteColumnByTableId(metadataId);
      metadataTableService.batchInsertColumn(columnList);
      metadataTableService.batchInsertHistoryColumn(historyColumnList);

      handleBusinessMetadata(oldMetadata, newVersion);

      // 发布完成，删除暂存区记录
      metadataColumnTmpService.deleteByMetadataId(metadataId);

      MetadataTmpDTO deleteParam = new MetadataTmpDTO();
      deleteParam.setMetadataId(metadataId);
      this.mapper.delete(deleteParam);
    }

    return true;
  }

  /**
   * 处理业务元数据
   *
   * @param oldMetadata 元数据
   * @param newVersion 元数据新版本
   */
  private void handleBusinessMetadata(BdpTableDTO oldMetadata, String newVersion) {

    List<String> businessCodeList = new ArrayList<>();
    businessCodeList.add("cName");
    businessCodeList.add("dataHierarchy");
    businessCodeList.add("domain");

    String dataSourceType = oldMetadata.getDataSourceType();
    if (DataSourceType.isRDBMS(dataSourceType)) {
      dataSourceType = "rdbms";
    }

    List<MetadataModelAttributeDTO> metadataModelAttributeList =
        metadataModelAttributeService.getListByDatasourceAndType(dataSourceType, businessCodeList);

    // 复制上个版本的业务元数据
    List<MetadataBusinessDto> metadataBusinessList = new ArrayList<>();
    for (MetadataModelAttributeDTO metadataModelAttributeDTO : metadataModelAttributeList) {
      if ("cName".equalsIgnoreCase(metadataModelAttributeDTO.getAttributeCode())) {
        String oldCName =
            metadataBusinessDao.getMetadataBusinessDetail(
                oldMetadata.getId(), "cName", oldMetadata.getTableVersion());
        if (StringUtils.isNotEmpty(oldCName)) {
          MetadataBusinessDto metadataBusinessCname = new MetadataBusinessDto();
          metadataBusinessCname.setId(ComUtil.getId());
          metadataBusinessCname.setTableId(oldMetadata.getId());
          metadataBusinessCname.setMetadataVersion(newVersion);
          metadataBusinessCname.setBusinessId(metadataModelAttributeDTO.getId());
          metadataBusinessCname.setValue(oldCName);
          EntityUtils.setCreateAndUpdateInfo(metadataBusinessCname);
          metadataBusinessList.add(metadataBusinessCname);
        }
      } else if ("dataHierarchy".equalsIgnoreCase(metadataModelAttributeDTO.getAttributeCode())) {
        String oldDataHierarchy =
            metadataBusinessDao.getMetadataBusinessDetail(
                oldMetadata.getId(), "dataHierarchy", oldMetadata.getTableVersion());
        if (StringUtils.isNotEmpty(oldDataHierarchy)) {
          MetadataBusinessDto metadataBusinessDataHierarchy = new MetadataBusinessDto();
          metadataBusinessDataHierarchy.setId(ComUtil.getId());
          metadataBusinessDataHierarchy.setTableId(oldMetadata.getId());
          metadataBusinessDataHierarchy.setMetadataVersion(newVersion);
          metadataBusinessDataHierarchy.setBusinessId(metadataModelAttributeDTO.getId());
          metadataBusinessDataHierarchy.setValue(oldDataHierarchy);
          EntityUtils.setCreateAndUpdateInfo(metadataBusinessDataHierarchy);
          metadataBusinessList.add(metadataBusinessDataHierarchy);
        }

      } else if ("domain".equalsIgnoreCase(metadataModelAttributeDTO.getAttributeCode())) {

        String oldDomain =
            metadataBusinessDao.getMetadataBusinessDetail(
                oldMetadata.getId(), "domain", oldMetadata.getTableVersion());
        if (StringUtils.isNotEmpty(oldDomain)) {
          MetadataBusinessDto metadataBusinessDomain = new MetadataBusinessDto();
          metadataBusinessDomain.setId(ComUtil.getId());
          metadataBusinessDomain.setTableId(oldMetadata.getId());
          metadataBusinessDomain.setMetadataVersion(newVersion);
          metadataBusinessDomain.setBusinessId(metadataModelAttributeDTO.getId());
          metadataBusinessDomain.setValue(oldDomain);
          EntityUtils.setCreateAndUpdateInfo(metadataBusinessDomain);
          metadataBusinessList.add(metadataBusinessDomain);
        }
      }
    }
    if (CollectionUtils.isNotEmpty(metadataBusinessList)) {
      metadataBusinessDao.batchInsertBusinessList(metadataBusinessList);
    }
  }
}
